import java.util.LinkedList;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.LockSupport;

/**
 * Author :  Rocky
 * Date : 25/05/2017 17:44
 * Description :
 * Test :
 */
public class NotBlockingQueue<T> {

    public LinkedList<T> innerQueue;

    private AtomicReference<Thread> currPutThread;

    private AtomicInteger currQueueSize;

    private int maxQueueSize;

    //自旋时间：5ms
    private int nanosTimeWhilePutOrTake = 5000000;

    //单位毫米
    private long[] sleepTimeLevle = new long[]{1, 2, 3, 5, 10};

    private long[] parkNanosLevel = new long[]{1, 2, 3, 5, 10, 20, 50, 100, 200, 500, 1000};

    public NotBlockingQueue(int maxQueueSize) {
        innerQueue = new LinkedList();
        currPutThread = new AtomicReference<>(null);
        currQueueSize = new AtomicInteger(0);
        this.maxQueueSize = maxQueueSize;
    }

    public void put(T t) {
        try {
            long nanosTimeout = nanosTimeWhilePutOrTake;
            long nanosEndTime = System.nanoTime() + nanosTimeout;

            //先自旋
            boolean becomePutThreadSuccess = false;
            while (!becomePutThreadSuccess && nanosTimeout > 0) {
                becomePutThreadSuccess = currPutThread.compareAndSet(null, Thread.currentThread());
                nanosTimeout = (nanosEndTime - System.nanoTime());
            }

            //还没成功，则按照sleep等级进行sleep
            if (!becomePutThreadSuccess) {
                for (int i = 0; i < sleepTimeLevle.length && !becomePutThreadSuccess; i++) {
                    becomePutThreadSuccess = currPutThread.compareAndSet(null, Thread.currentThread());
                    try {
                        Thread.sleep(sleepTimeLevle[i]);
                    } catch (InterruptedException e) {

                    }
                }
            }

            //如果还没成功，则 给put线程发送中断请求,然后递归
            if (!becomePutThreadSuccess) {
                currPutThread.get().interrupt();
                put(t);
            }

            //到这里就成功了

            //如果队列满了，则再次spin
            nanosEndTime = System.nanoTime() + nanosTimeout;
            while (nanosTimeout > 0 && currQueueSize.get() > maxQueueSize) {
                nanosTimeout = (nanosEndTime - System.nanoTime());
            }

            //如果队列未满，则加入队尾
            for (int i = 0; i < parkNanosLevel.length && currQueueSize.get() >= maxQueueSize; i++) {
                LockSupport.parkNanos(parkNanosLevel[i]);
            }

            while (currQueueSize.get() >= maxQueueSize) {
                LockSupport.parkNanos(parkNanosLevel[parkNanosLevel.length - 1]);
            }

            innerQueue.addLast(t);
            currQueueSize.incrementAndGet();
            //释放锁
            currPutThread.compareAndSet(Thread.currentThread(), null);
        } catch (Throwable e) {
            System.out.println("入队异常 " + e.getMessage());
        }
    }


    public T take() {
        try {
            T t = innerQueue.removeFirst();
            currQueueSize.decrementAndGet();
            return t;
        } catch (Exception e) {
            System.out.println("take a null object");
//            e.printStackTrace();
            return null;
        }
    }


}
